package mapelements.foreground;

import java.awt.Shape;
import java.lang.reflect.InvocationTargetException;

import mapelements.MapElement;
import mapelements.Renderer;

import errors.FactoryFailureException;


/**
 * 
 * @author Koldar
 *
 * @param <RENDERER>
 * @version 1.5
 */
public abstract class Foreground<RENDERER extends Renderer> extends MapElement<RENDERER>{
	
	private static final long serialVersionUID = -3291978073506853174L;
	
	/**rappresenta la forma che il Foreground possiede all'interno di uno strato della
	 * mappa. La forma è assolutamente indispensabile per capire se un oggetto deve subire
	 * degli effetti o meno di un particolare settore dello spazio. Per esempio, la forma è indispensabile
	 * per capire se un personaggio sull'orlo di un baratro debba cadere oppure no.
	 * <p>Quale sia il senso delle coordinate specificate dalla forma attribuita al foreground poi è
	 * abbastanza ambiguo: in genere sarebbe consigliato che tali coordinate siano coordinate rispetto
	 * alla <tt>mapresolution</tt> della mappa a cui il foreground appartiene (in modo da rendere il
	 * foreground molto scalabile)
	 */
	protected Shape shape;
	/**rappresenta la classe che si occupa di inoltrare i messaggi relativi a questo Foreground*/
	private ForegroundEventDispatcher dispatcher;
	/*l'oggetto dispatcher va salvato perché in questo modo al "open" c'è già un'istanza di dispatcher del foreground che può essere usata. Se il dispatcher
	 * è un BeeDispatcher è diverso da un comune ForegroundEventDispatcher!!!
	 */ 
	
	public Foreground(RENDERER _renderer,Shape _shape,AbstractForegroundDispatcherFactory factory){
		super(_renderer);
		this.shape=_shape;
		try {
			this.dispatcher=factory.newForegroundDispatcher();
		} catch (FactoryFailureException error) {
			error.printStackTrace();
		}
	}
	
	public Foreground(RENDERER _renderer,Shape _shape,ForegroundEventDispatcher dispatcher){
		super(_renderer);
		this.shape=_shape;
		this.dispatcher=dispatcher;
	}
	
	public Foreground(RENDERER _renderer,Shape _shape){
		this(_renderer,_shape,new DefaultForegroundDispatcherFactory());
	}
	
	public Foreground(Shape _shape){
		this(null,_shape,new DefaultForegroundDispatcherFactory());
	}
	
	public Foreground<RENDERER> clone() throws CloneNotSupportedException{
		Foreground result=(Foreground<RENDERER>) super.clone();
		//tento di evocare il metodo clone() (se esiste) del tipo dinamico di shape
		try {
			result.shape=(Shape) this.shape.getClass().getMethod("clone").invoke(this);
		} catch (IllegalAccessException | IllegalArgumentException| InvocationTargetException | NoSuchMethodException| SecurityException error) {
			System.out.println("la shape non è stata clonata!");
			result.shape=null;
		} catch (NullPointerException shapenull){
			result.shape=null;
		}
		result.dispatcher=this.dispatcher.clone();
		return result;
	}
	
	/**
	 * @return the shape. For further information visit {@link #shape}
	 */
	public Shape getShape() {
		return shape;
	}
	
	/**
	 * 
	 * @return le coordinate assolute (in mapResolution) che indicano la posizione ASSOLUTA del foreground. Di default questo metodo
	 * restituisce {@link #shape}
	 * @throws UnsupportedOperationException in caso l'operazione non possa essere completata per un qualche motivo non ben specificato. Di default
	 * eccezione non si manifesta mai
	 */
	public Shape getAbsoluteShape() throws UnsupportedOperationException{
		return shape;
	}

	/**
	 * @param shape the shape to set
	 */
	public void setShape(Shape shape) {
		this.shape = shape;
	}

}
